#!/usr/bin/python2.5
#
# Written by:
# 	Michael Sander | michael.sander@gmail.com
# 	Let me know if you like it!
#
# Licensed Under GPLv3
#
#	 Copyright (C) 2010  Michael Sander
#
#    This program is free software: you can redistribute it and/or modify
#    it under the terms of the GNU General Public License as published by
#    the Free Software Foundation, either version 3 of the License, or
#    (at your option) any later version.
#
#    This program is distributed in the hope that it will be useful,
#    but WITHOUT ANY WARRANTY; without even the implied warranty of
#    MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
#    GNU General Public License for more details.
#
#    You should have received a copy of the GNU General Public License
#    along with this program.  If not, see <http://www.gnu.org/licenses/>.
import logging, copy;

DEBUG = True;	
def query_IN_with_cursor(q, search_for, in_search_array, max_fetch, with_cursor = None):
	'''
	Implements the following functionality:
			q.filter(search_for + " IN", in_search_array);
			q.with_cursor(with_cursor);
			results = q.fetch(max_fetch);
			return (results, q.cursor());
	The above code will not work, you get the following exception:
		No cursor available for a MultiQuery (queries using \"IN\" or \"!=\" operators)
	I work around this limitation by doing some record keeping within the cursor.
	'''
	
	(cur_search_item, cur_search_cursor) = (0, None);
	if(with_cursor != None):
		(cur_search_item, cur_search_cursor) = with_cursor;
		if(cur_search_item >= len(in_search_array)):
			raise Exception("Cursor must be less than %d."%len(in_search_array));
	if(DEBUG):
		logging.debug("query_IN_with_cursor: Querying "
					 "'%s' = %s (%d/%d). %s cursor."%\
				(search_for, str(in_search_array[cur_search_item]), 
				cur_search_item, len(in_search_array),
				"W/" if cur_search_cursor else "W/o",
				));
		#logging.info("query_IN_with_cursor: %s"%str(cur_search_cursor));
	
	# Create a deep copy of the query before we mess with it
	q_copy = copy.deepcopy(q);			
	# Here run the query on the current element. We do a '=' query
	# on each element rather than a 'IN' query on an array of them.
	q = q.filter(search_for + " = ", in_search_array[cur_search_item]);
	
	if(cur_search_cursor != None):
		q.with_cursor(cur_search_cursor);
	else:
		q.with_cursor(None);
	#results = list(q.run());
	results = q.fetch(limit = max_fetch)
	cursor = q.cursor();
	
	if(DEBUG):
		logging.info("query_IN_cursor: Queried "
					 "'%s'=%s  (%d/%d). %s cursor. Got %d results (max=%d)."%\
				(search_for, str(in_search_array[cur_search_item]),
				cur_search_item, len(in_search_array),
				"W/" if cur_search_cursor else "W/o",
				 len(results), max_fetch));
		#logging.info("query_IN_with_cursor: %s"%str(cursor));
	if(len(results) > max_fetch):
		# This should never happen
		raise Exception("Google App Store fetch problem");
	
	if(len(results) == max_fetch):
		# There is more data left in this element. Return the results 
		return (results, (cur_search_item, cursor));
	
	if(cur_search_item == len(in_search_array) - 1):
		# We have searched through all array elements. Nothing left to search.
		return (results, (cur_search_item, cursor));
	
	# We've hit the end of the data in the current array item and there's more.
	# Make a recursive call to get data out of the next array item.
	# 	Reduce max_fetch by the amount that we already fetched
	#	In the next item in the array
	# May result in several recursive calls, but not more than len(in_search_array)
	(new_results, new_cursor) = query_IN_with_cursor(q_copy, search_for, 
		in_search_array, max_fetch - len(results), 
		(cur_search_item + 1, None));
	
	# Now merge the results together and return
	return (results + new_results, new_cursor);
